"""
数字迷宫游戏主程序
实现一个基于数字合并的益智游戏，玩家通过移动方块进行数字合并
"""

import pygame
import sys
import random
from renderer import GridRenderer  # 网格渲染器
from number_block import NumberBlock  # 数字方块和运算符方块


class DigitalMazeGame:
    """
    数字迷宫游戏主类
    管理游戏状态、渲染、逻辑和用户输入
    """

    def __init__(self):
        """
        初始化游戏实例
        设置游戏窗口、初始状态和游戏元素
        包括:
        - 屏幕尺寸和标题
        - 游戏时钟
        - 游戏状态和分数
        - 目标分数
        - 网格渲染器
        - 初始数字方块
        - 运算符方块
        - 顶部五个格子数组
        - 最近合并的方块类型记录
        """
        self.target_score = 2048  # 目标分数
        self.last_merged_types = "number"  # 记录最近合并的方块类型
        self.track_merge_sequence = True  # 跟踪合并顺序
        self.allow_operator_merge = False  # 是否允许合并运算符
        pygame.init()
        self.screen_width = 800
        self.screen_height = 600
        self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
        pygame.display.set_caption("数字迷宫")
        self.clock = pygame.time.Clock()
        self.running = True
        self.score = 0
        self.merge_count = 0  # 初始化合并计数器
        self.game_state = "playing"  # playing, win, lose
        self.game_mode = "endless"  # endless, classic
        # 尝试加载支持中文的字体(调整为24号字)
        try:
            self.font = pygame.font.SysFont("SimHei", 24)  # 黑体
        except:
            try:
                self.font = pygame.font.SysFont("Microsoft YaHei", 24)  # 微软雅黑
            except:
                self.font = pygame.font.SysFont(None, 24)  # 回退到默认字体
        self.grid_size = 10
        self.cell_size = 50

        # 初始化顶部格子状态数组(4个元素对应4个格子)
        self.top_grid_values = [None, None, None, "="]

        # 初始化顶部五个格子数组
        self.top_grids = [
            {
                "x": 0,
                "y": 0,
                "width": self.cell_size,
                "height": self.cell_size,
                "value": None,
            },
            {
                "x": 0,
                "y": 0,
                "width": self.cell_size,
                "height": self.cell_size,
                "value": None,
            },
            {
                "x": 0,
                "y": 0,
                "width": self.cell_size,
                "height": self.cell_size,
                "value": None,
            },
            {
                "x": 0,
                "y": 0,
                "width": self.cell_size,
                "height": self.cell_size,
                "value": "=",
            },
            {
                "x": 0,
                "y": 0,
                "width": self.cell_size,
                "height": self.cell_size,
                "value": None,
            },
        ]

        # 初始化网格渲染器 (10x10网格，每个单元格50像素)
        self.grid_renderer = GridRenderer(grid_width=10, grid_height=10, cell_size=50)

        # 初始化数字方块列表
        grid_width = 10  # 网格宽度
        grid_height = 10  # 网格高度
        player_block = NumberBlock(
            value=random.choice([2, 4]),
            row=5,
            col=5,
            cell_size=50,
            font=self.font,
            grid_width=grid_width,
            grid_height=grid_height,
            is_player=True,
        )
        player_block.movable = True  # 设置玩家方块可移动

        self.top_grid_values[0] = player_block.value
        self.top_grids[0]["value"] = player_block.value

        self.number_blocks = [
            player_block,  # 玩家控制的方块
            NumberBlock(
                value=2,
                row=3,
                col=3,
                cell_size=50,
                font=self.font,
                grid_width=grid_width,
                grid_height=grid_height,
            ),  # 相同数字测试1
            NumberBlock(
                value=4,
                row=7,
                col=7,
                cell_size=50,
                font=self.font,
                grid_width=grid_width,
                grid_height=grid_height,
            ),  # 相同数字测试2
            NumberBlock(
                value=4,
                row=2,
                col=2,
                cell_size=50,
                font=self.font,
                grid_width=grid_width,
                grid_height=grid_height,
            ),  # 相同数字测试3
        ]

        # 添加2个固定运算符方块(使用字符串类型)
        operators = ["+", "-", "*", "/"]
        random.shuffle(operators)
        for i in range(2):
            # 找出所有空位置
            occupied = {(block.row, block.col) for block in self.number_blocks}
            empty_positions = [
                (row, col)
                for row in range(grid_height)
                for col in range(grid_width)
                if (row, col) not in occupied
            ]

            if empty_positions and operators:
                row, col = random.choice(empty_positions)
                operator = operators.pop()
                self.number_blocks.append(
                    NumberBlock(
                        operator=operator,  # 直接使用字符串运算符
                        row=row,
                        col=col,
                        cell_size=50,
                        font=self.font,
                        block_type="operator",
                        grid_width=grid_width,
                        grid_height=grid_height,
                    )
                )

        self.generate_equal_block()


    def get_movable_blocks(self, direction):
        """获取可以朝指定方向移动的方块"""
        movable_blocks = []
        for block in self.number_blocks:
            # 检查方块是否可以朝该方向移动
            new_row, new_col = block.row, block.col
            if direction == "up":
                new_row = max(0, block.row - 1)
            elif direction == "down":
                new_row = min(self.grid_size - 1, block.row + 1)
            elif direction == "left":
                new_col = max(0, block.col - 1)
            elif direction == "right":
                new_col = min(self.grid_size - 1, block.col + 1)

            # 检查新位置是否为空
            position_occupied = any(
                b.row == new_row and b.col == new_col
                for b in self.number_blocks
                if b != block
            )
            if not position_occupied:
                movable_blocks.append(block)
        return movable_blocks

    def handle_events(self):
        """
        处理所有用户输入事件
        包括:
        - 键盘方向键控制方块移动
        - ESC键退出游戏
        - 数字键选择游戏模式
        - 窗口关闭事件

        返回:
        - 无返回值，但会更新游戏状态
        """
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False

        # 持续移动控制
        if self.game_state != "playing":
            return

        # 获取玩家方块
        player_block = next((b for b in self.number_blocks if b.is_player), None)
        if not player_block:
            return

        # 设置移动间隔(毫秒)
        move_delay = 150  # 150毫秒移动一次
        current_time = pygame.time.get_ticks()

        if not hasattr(self, "last_move_time"):
            self.last_move_time = 0

        if current_time - self.last_move_time > move_delay:
            keys = pygame.key.get_pressed()
            moved = False

            if keys[pygame.K_UP] or keys[pygame.K_w]:
                player_block.move("up", self.number_blocks)
                moved = True
            elif keys[pygame.K_DOWN] or keys[pygame.K_s]:
                player_block.move("down", self.number_blocks)
                moved = True
            elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
                player_block.move("left", self.number_blocks)
                moved = True
            elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
                player_block.move("right", self.number_blocks)
                moved = True

            if moved:
                self.last_move_time = current_time
                self.check_collisions()

    def update(self):
        pass

    def check_collisions(self):
        """
        检查并处理方块的碰撞和合并
        逻辑包括:
        1. 检测相邻的相同数字方块
        2. 合并符合条件的方块(相同数字相加)
        3. 根据合并结果更新分数:
           - 基础分: 合并后的数字值
           - 连击加成: 连续合并的额外奖励
        4. 在随机位置生成新方块

        注意:
        - 每个方块每回合只能合并一次
        - 合并后原方块会被移除
        """
        """检查所有方块的碰撞并处理合并"""
        if len(self.number_blocks) < 2:  # 至少需要两个方块才能碰撞
            return

        merged = True
        while merged:  # 循环直到没有合并发生
            merged = False
            blocks_to_remove = set()
            new_blocks = []

            # 找出所有玩家方块
            player_blocks = [b for b in self.number_blocks if b.is_player]
            if not player_blocks:
                return

            player_block = player_blocks[0]  # 取第一个玩家方块

            # 检查玩家方块与其他方块的碰撞
            for i, block in enumerate(self.number_blocks):

                if (
                    block != player_block
                    and block.row == player_block.row
                    and block.col == player_block.col
                ):
                    print(f"碰撞: {player_block.type}, {player_block.to_merge}, {player_block.col}")
                        # 记录合并的方块类型
                    self.last_merged_types = block.type
                    if block.type == "operator":
                        # 合并运算符方块时保留玩家方块的数字值
                        new_value = block.value
                        new_block = NumberBlock(
                            value=new_value,
                            operator=block.operator,
                            row=player_block.row,
                            col=player_block.col,
                            cell_size=player_block.cell_size,
                            font=self.font,
                            grid_width=10,
                            grid_height=10,
                            is_player=True,
                            movable=True,
                            just_merged=True,
                            block_type="operator",
                            to_merge=True,
                        )
                        # 更新顶部第二个格子为运算符
                        self.top_grid_values[1] = block.operator
                        self.top_grids[1]["value"] = block.operator
                        # 分数增加运算符的固定值
                        # self.score += 10
                    elif block.type == "equal":
                        new_value = block.value
                        new_block = NumberBlock(
                            value=new_value,
                            operator=block.operator,
                            row=player_block.row,
                            col=player_block.col,
                            cell_size=player_block.cell_size,
                            font=self.font,
                            grid_width=10,
                            grid_height=10,
                            is_player=True,
                            movable=True,
                            just_merged=True,
                            block_type="equal",
                            to_merge=True,
                        )
                        self.top_grid_values = [None, None, None, "="]
                    else:
                        # 合并数字方块时计算新值
                        new_value = player_block.value + block.value
                        new_block = NumberBlock(
                            value=new_value,
                            row=player_block.row,
                            col=player_block.col,
                            cell_size=player_block.cell_size,
                            font=self.font,
                            grid_width=10,
                            grid_height=10,
                            is_player=True,
                            movable=True,
                            just_merged=True,
                        )
                        # 更新顶部第一个格子的值为角色方块的值
                        if hasattr(player_block, "operator"):
                            self.top_grid_values[2] = block.value
                            self.top_grids[2]["value"] = block.value
                        else  :
                            self.top_grid_values[0] = block.value
                            self.top_grids[0]["value"] = block.value

                    new_blocks.append(new_block)

                    # 重置所有方块的just_merged状态
                    for block in self.number_blocks:
                        if hasattr(block, "just_merged"):
                            block.just_merged = False
                    blocks_to_remove.add(self.number_blocks.index(player_block))
                    blocks_to_remove.add(i)
                    # self.score += player_block.value
                    self.merge_count += 1  # 增加合并计数
                    merged = True
                    print(
                        f"合并成功! 新数字: {new_value}, 得分: +{player_block.value}, 合并次数: {self.merge_count}"
                    )

                    # 检查胜利条件
                    if self.game_mode == "classic" and self.score >= 2048:
                        self.game_state = "win"
                        print("恭喜获胜！你合并出了2048！")

                    print(f"当前顶部格子值: {self.top_grid_values}")
                    # 检查所有格子是否都有值
                    if all(value is not None for value in self.top_grid_values):
                        print("所有顶部格子都已填充值！")
                        new_block.to_merge = False
                    else:
                        new_block.to_merge = True

                    break


            # 处理方块变更
            if merged:
                # 添加新方块
                self.number_blocks.extend(new_blocks)

                # 移除被合并的方块
                for index in sorted(blocks_to_remove, reverse=True):
                    if index < len(self.number_blocks):
                        removed_block = self.number_blocks.pop(index)
                        print(
                            f"已移除方块: 值={removed_block.value}, 位置=({removed_block.row},{removed_block.col})"
                        )


                # 生成新方块
                self.generate_new_block()
                # 随机生成运算符方块
                if player_block.type == "operator":
                    self.generate_new_random_operator_block()

                print("123",player_block.to_merge)
                if new_block.type == "equal":
                    self.generate_equal_block()

                    new_value = self.calculate_top_grid()
                    self.score += new_value
                    # 重置顶部格子值
                    self.top_grid_values = [None, None, None, "="]
                    # 更新顶部格子显示
                    self.top_grids[4]["value"] = new_value
                    for i, grid in enumerate(self.top_grids):
                        if i < 3:
                            grid["value"] = None  # 设为None而不是空字符串

                # if new_block.type == "eq":
                    # self.generate_equal_block()

                # 检查玩家数字是否存在于其他方块中
                # player_block = next(
                #     (b for b in self.number_blocks if b.is_player), None
                # )
                # if player_block:
                #     value_exists = any(
                #         block.value == player_block.value and not block.is_player
                #         for block in self.number_blocks
                #     )
                #     # 如果不存在，生成相同数字的方块
                #     if not value_exists:
                #         self.spawn_matching_block()

                # 打印当前top_grid_values状态

    def can_merge_any(self):
        """检查是否还有可能的合并"""
        if len(self.number_blocks) < 2:
            return False

        # 检查玩家方块是否能与任何方块合并
        player_block = self.number_blocks[0]
        for block in self.number_blocks[1:]:
            if player_block.value == block.value:
                return True

        # 检查其他方块之间是否能合并
        for i in range(1, len(self.number_blocks)):
            for j in range(i + 1, len(self.number_blocks)):
                if (
                    self.number_blocks[i].row == self.number_blocks[j].row
                    and self.number_blocks[i].col == self.number_blocks[j].col
                    and self.number_blocks[i].value == self.number_blocks[j].value
                ):
                    return True
        return False

    def spawn_matching_block(self):
        """在空白位置生成与玩家方块相同数字的方块"""
        # 获取玩家方块
        player_block = next((b for b in self.number_blocks if b.is_player), None)
        if not player_block:
            return

        # 获取所有空白位置
        occupied = {(block.row, block.col) for block in self.number_blocks}
        empty_positions = [
            (row, col)
            for row in range(self.grid_renderer.grid_height)
            for col in range(self.grid_renderer.grid_width)
            if (row, col) not in occupied
        ]

        # 如果有空白位置，随机选择一个生成新方块
        if empty_positions:
            row, col = random.choice(empty_positions)
            self.number_blocks.append(
                NumberBlock(
                    value=player_block.value,
                    row=row,
                    col=col,
                    cell_size=self.grid_renderer.cell_size,
                    font=self.font,
                    grid_width=10,
                    grid_height=10,
                    is_player=False,
                    movable=True,
                )
            )
            print(f"生成匹配方块: 值={player_block.value}, 位置=({row},{col})")

    def generate_new_block(self):
        """
        在网格中生成新方块
        生成规则:
        1. 随机选择空网格位置
        2. 80%概率生成数字2
        3. 20%概率生成数字4
        4. 每100分有5%概率生成特殊运算符方块

        特殊处理:
        - 确保新方块不与现有方块重叠
        - 当网格接近填满时调整生成策略

        返回:
        - 新生成的方块对象
        """
        """在随机空位置生成一个新方块"""
        occupied = {(block.row, block.col) for block in self.number_blocks}
        empty_positions = [
            (row, col)
            for row in range(self.grid_renderer.grid_height)
            for col in range(self.grid_renderer.grid_width)
            if (row, col) not in occupied
        ]

        if empty_positions:
            row, col = random.choice(empty_positions)
            new_value = random.choice([2, 4, 8, 16])  # 生成随机数字(2,4,8,16)
            self.number_blocks.append(
                NumberBlock(
                    value=new_value,
                    row=row,
                    col=col,
                    cell_size=self.grid_renderer.cell_size,
                    font=self.font,
                    grid_width=10,
                    grid_height=10,
                )
            )
            # print(f"生成新方块: 值={new_value}, 位置=({row},{col})")
        else:
            # 检查是否还有可能的合并
            if not self.can_merge_any():
                self.game_state = "lose"
                print("游戏结束！无法继续合并！")

    def generate_new_random_operator_block(self):
        """
        在网格中生成新方块
        生成规则:
        1. 随机选择空网格位置
        2. 80%概率生成数字2
        3. 20%概率生成数字4
        4. 每100分有5%概率生成特殊运算符方块

        特殊处理:
        - 确保新方块不与现有方块重叠
        - 当网格接近填满时调整生成策略

        返回:
        - 新生成的方块对象
        """
        """在随机空位置生成一个新方块"""
        occupied = {(block.row, block.col) for block in self.number_blocks}
        empty_positions = [
            (row, col)
            for row in range(self.grid_renderer.grid_height)
            for col in range(self.grid_renderer.grid_width)
            if (row, col) not in occupied
        ]

        if empty_positions:
            row, col = random.choice(empty_positions)
            # 10%概率生成运算符方块
            # if random.random() < 0.4:
            operator = random.choice(["+", "-", "*", "/"])
            self.number_blocks.append(
                NumberBlock(
                    operator=operator,
                    row=row,
                    col=col,
                    cell_size=self.grid_renderer.cell_size,
                    font=self.font,
                    block_type="operator",
                    grid_width=10,
                    grid_height=10,
                )
            )
                # print(f"生成运算符方块: 运算符={operator}, 位置=({row},{col})")
        else:
            # 检查是否还有可能的合并
            if not self.can_merge_any():
                self.game_state = "lose"
                print("游戏结束！无法继续合并！")

    def generate_equal_block(self):
        """专门生成'='方块"""
        occupied = {(block.row, block.col) for block in self.number_blocks}
        empty_positions = [
            (row, col)
            for row in range(self.grid_renderer.grid_height)
            for col in range(self.grid_renderer.grid_width)
            if (row, col) not in occupied
        ]

        if empty_positions:
            row, col = random.choice(empty_positions)
            self.number_blocks.append(
                NumberBlock(
                    operator="=",
                    row=row,
                    col=col,
                    cell_size=self.grid_renderer.cell_size,
                    font=self.font,
                    block_type="equal",
                    grid_width=10,
                    grid_height=10,
                )
            )
            return True
        return False

    def render(self):
        """
        渲染游戏画面
        渲染顺序:
        1. 清空屏幕(填充背景色)
        2. 绘制游戏网格
        3. 绘制所有数字方块
        4. 绘制UI元素:
           - 当前分数
           - 游戏模式
           - 剩余时间(限时模式)
           - 游戏状态提示(胜利/失败)
        5. 更新显示

        注意:
        - 使用GridRenderer处理网格渲染
        - 不同游戏状态显示不同UI
        """
        # 清空屏幕
        self.screen.fill((255, 255, 255))

        # 使用网格渲染器绘制网格
        self.grid_renderer.render(self.screen)

        # 计算网格偏移量(用于数字方块定位)
        offset_x, offset_y = self.grid_renderer.calculate_grid_position(
            self.screen_width, self.screen_height
        )

        # 渲染所有数字方块
        for block in self.number_blocks:
            block.render(
                self.screen, offset_x, offset_y
            )  # 颜色由NumberBlock类根据movable属性决定

        # 绘制顶部五个格子
        self.draw_top_grids()

    def calculate_top_grid(self):
        """计算顶部格子的运算结果

        返回:
            int|None: 计算结果(整数)，如果无法计算则返回None
        """
        # 检查所有值都存在
        if not all(self.top_grid_values[:3]):
            return None

        try:
            num1 = float(self.top_grid_values[0])
            num2 = float(self.top_grid_values[2])
            operator = self.top_grid_values[1]

            if operator == '+':
                return int(num1 + num2)
            elif operator == '-':
                return int(num1 - num2)
            elif operator == '*':
                return int(num1 * num2)
            elif operator == '/':
                if num2 == 0:
                    return None  # 除零保护
                return int(round(num1 / num2))  # 除法结果四舍五入后取整
            else:
                return None  # 未知运算符
        except (ValueError, TypeError):
            return None

    def draw_top_grids(self):
        """绘制顶部五个格子"""
        grid_spacing = 10  # 格子间距10px
        grid_width = 5 * self.cell_size + 4 * grid_spacing
        start_x = (self.screen_width - grid_width) // 2
        start_y = 10  # 与地图保持40px距离

        for i, grid in enumerate(self.top_grids):
            # 更新格子位置
            grid["x"] = start_x + i * (self.cell_size + grid_spacing)
            grid["y"] = start_y

            # 绘制格子背景和边框
            pygame.draw.rect(
                self.screen,
                (255, 255, 255),
                (grid["x"], grid["y"], grid["width"], grid["height"]),
            )
            pygame.draw.rect(
                self.screen,
                (200, 200, 200),
                (grid["x"], grid["y"], grid["width"], grid["height"]),
                1,
            )

            # 绘制格子内容
            if grid["value"]:
                text_surface = self.font.render(str(grid["value"]), True, (0, 0, 0))
                text_rect = text_surface.get_rect(
                    center=(
                        grid["x"] + grid["width"] // 2,
                        grid["y"] + grid["height"] // 2,
                    )
                )
                self.screen.blit(text_surface, text_rect)

        # 绘制游戏UI信息(全部在左上角)
        ui_elements = [
            (
                f'模式: {"无尽" if self.game_mode == "endless" else "经典"}',
                (0, 128, 255),
                20,
                10,
            ),
            (f"分数: {self.score}", (0, 128, 255), 50, 10),  # 下移30像素
            (f"合并: {self.merge_count}", (0, 128, 255), 80, 10),  # 下移30像素
        ]

        for text, color, y_pos, x_pos in ui_elements:
            text_surface = self.font.render(text, True, color)
            self.screen.blit(text_surface, (x_pos, y_pos))

        # 绘制目标分数
        target_text = f"目标分数: {self.target_score}"
        target_x = start_x + grid_width + 20  # 五个格子右侧20px
        target_y = start_y + self.cell_size // 2 - 10  # 垂直居中
        text_surface = self.font.render(target_text, True, (255, 255, 0))  # 黄色文字
        self.screen.blit(text_surface, (target_x, target_y))

        # 绘制游戏状态
        if self.game_state == "win":
            state_text = self.font.render("胜利！按任意键退出", True, (0, 255, 0))
            self.screen.blit(state_text, (self.screen_width // 2 - 100, 20))
        elif self.game_state == "lose":
            state_text = self.font.render("游戏结束！按任意键退出", True, (255, 0, 0))
            self.screen.blit(state_text, (self.screen_width // 2 - 120, 20))


        pygame.display.flip()

    def run(self):
        """
        游戏主循环
        执行流程:
        1. 处理用户输入事件
        2. 根据游戏状态更新游戏逻辑:
           - 菜单状态: 等待模式选择
           - 游戏状态: 更新方块位置和状态
           - 结束状态: 显示结果
        3. 检测并处理方块碰撞
        4. 渲染当前游戏画面
        5. 控制帧率(60FPS)

        循环终止条件:
        - 用户退出游戏
        - 游戏结束状态超时
        """
        while self.running:
            self.handle_events()
            self.update()
            self.render()
            self.clock.tick(60)  # 60 FPS



if __name__ == "__main__":
    game = DigitalMazeGame()
    game.run()
    pygame.quit()
    sys.exit()